package xin.ryven.workflow.controller;

import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.context.SecurityContextHolder;
import xin.ryven.workflow.dto.ErrorResponse;
import xin.ryven.workflow.dto.ProcessStartDTO;
import xin.ryven.workflow.model.ApprovalHistory;
import xin.ryven.workflow.model.FormField;
import xin.ryven.workflow.model.ProcessRequest;
import xin.ryven.workflow.security.UserDetailsImpl;
import xin.ryven.workflow.service.ProcessService;
import org.camunda.bpm.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/process")
@CrossOrigin
@Slf4j
public class ProcessController {

    @Autowired
    private ProcessService processService;

    @Autowired
    private RepositoryService repositoryService;

    @PostMapping("/start")
    public ResponseEntity<?> startProcess(@RequestBody Map<String, Object> request) {
        try {
            String processDefinitionId = (String) request.get("processDefinitionId");
            Map<String, Object> variables = (Map<String, Object>) request.get("variables");
            
            // 获取当前用户
            UserDetailsImpl userDetails = (UserDetailsImpl) SecurityContextHolder
                .getContext()
                .getAuthentication()
                .getPrincipal();
                
            // 添加发起人变量
            variables.put("initiator", userDetails.getId());
            
            // 创建流程请求记录
            ProcessRequest processRequest = processService.startProcess(processDefinitionId, variables);
            
            return ResponseEntity.ok(processRequest);
        } catch (Exception e) {
            log.error("Start process failed", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("启动流程失败: " + e.getMessage()));
        }
    }

    @GetMapping("/tasks")
    public ResponseEntity<List<Map<String, Object>>> getMyTasks() {
        // 获取当前用户
        UserDetailsImpl userDetails = (UserDetailsImpl) SecurityContextHolder
            .getContext()
            .getAuthentication()
            .getPrincipal();
        
        List<Task> tasks = processService.getMyTasks(userDetails.getId().toString());
        
        // 转换任务信息，添加流程变量
        List<Map<String, Object>> result = tasks.stream()
            .map(task -> {
                Map<String, Object> taskInfo = new HashMap<>();
                taskInfo.put("id", task.getId());
                taskInfo.put("name", task.getName());
                taskInfo.put("createTime", task.getCreateTime());
                taskInfo.put("processInstanceId", task.getProcessInstanceId());
                
                // 获取流程变量
                Map<String, Object> variables = processService.getProcessVariables(task.getProcessInstanceId());
                taskInfo.put("variables", variables);
                
                // 获取任务表单数据
                Map<String, Object> formData = processService.getTaskFormData(task.getId());
                taskInfo.put("formData", formData);
                
                return taskInfo;
            })
            .collect(Collectors.toList());
        
        return ResponseEntity.ok(result);
    }

    @GetMapping("/tasks/{taskId}/form-data")
    public ResponseEntity<?> getTaskFormData(@PathVariable String taskId) {
        try {
            Map<String, Object> formData = processService.getTaskFormData(taskId);
            return ResponseEntity.ok(formData);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("获取任务表单数据失败: " + e.getMessage()));
        }
    }

    @PostMapping("/tasks/{taskId}/complete")
    public ResponseEntity<?> completeTask(
            @PathVariable String taskId,
            @RequestBody Map<String, Object> variables) {
        try {
            processService.completeTask(taskId, variables);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("完成任务失败: " + e.getMessage()));
        }
    }

    @PostMapping("/process-definitions/deploy")
    public ResponseEntity<?> deployProcessDefinition(
            @RequestParam("key") String key,
            @RequestParam("file") MultipartFile file) {
        try {
            String bpmnXml = new String(file.getBytes(), StandardCharsets.UTF_8);
            processService.saveProcessDefinition(key, bpmnXml);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            log.error("Failed to deploy process definition", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("Failed to deploy process definition: " + e.getMessage());
        }
    }

    @PutMapping("/process-definitions/{id}")
    public ResponseEntity<?> updateProcessDefinition(
            @PathVariable String id,
            @RequestParam("key") String key,
            @RequestParam("file") MultipartFile file) {
        try {
            String bpmnXml = new String(file.getBytes(), StandardCharsets.UTF_8);
            processService.updateProcessDefinition(id, key, bpmnXml);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            log.error("Failed to update process definition", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("更新流程定义失败: " + e.getMessage()));
        }
    }

    @GetMapping("/process-definitions")
    public ResponseEntity<List<Map<String, Object>>> getProcessDefinitions() {
        List<ProcessDefinition> definitions = repositoryService.createProcessDefinitionQuery()
                .latestVersion()
                .list();

        List<Map<String, Object>> result = definitions.stream()
                .map(def -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("id", def.getDeploymentId());
                    map.put("processDefinitionId", def.getId());
                    map.put("key", def.getKey());
                    map.put("name", def.getName());
                    map.put("version", def.getVersion());
                    map.put("description", def.getDescription());
                    Deployment deployment = repositoryService.createDeploymentQuery()
                            .deploymentId(def.getDeploymentId())
                            .singleResult();
                    map.put("createdAt", deployment != null ? deployment.getDeploymentTime() : null);
                    return map;
                })
                .collect(Collectors.toList());

        return ResponseEntity.ok(result);
    }

    @GetMapping("/process-definitions/{id}/form-config")
    public ResponseEntity<?> getProcessFormConfig(@PathVariable String id) {
        try {
            Map<String, Object> formConfig = processService.getProcessFormConfig(id);
            return ResponseEntity.ok(formConfig);
        } catch (Exception e) {
            log.error("Failed to get form config", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("获取表单配置失败: " + e.getMessage()));
        }
    }

    @PostMapping("/process-definitions/{id}/form-config")
    public ResponseEntity<?> saveProcessFormConfig(
            @PathVariable String id,
            @RequestBody List<FormField> fields) {
        try {
            processService.saveProcessFormConfig(id, fields);
            // 保存后立即返回最新的配置
            Map<String, Object> formConfig = processService.getProcessFormConfig(id);
            return ResponseEntity.ok(formConfig);
        } catch (Exception e) {
            log.error("Failed to save form config", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("保存表单配置失败: " + e.getMessage()));
        }
    }

    @GetMapping("/process-instances/{processInstanceId}/history")
    public ResponseEntity<?> getProcessHistory(@PathVariable String processInstanceId) {
        try {
            List<ApprovalHistory> history = processService.getProcessHistory(processInstanceId);
            return ResponseEntity.ok(history);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("获取审批历史失败: " + e.getMessage()));
        }
    }

    @GetMapping("/process-definitions/bpmn")
    public ResponseEntity<String> getProcessBpmnXml(@RequestParam String id) {
        try {
            String bpmnXml = processService.getProcessDefinitionXml(id);
            return ResponseEntity.ok(bpmnXml);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body("流程定义未找到: " + e.getMessage());
        }
    }

    @PostMapping("/process-instances")
    public ResponseEntity<Void> startProcess(@RequestBody ProcessStartDTO dto) {
        try {
            // 获取当前用户
            UserDetailsImpl userDetails = (UserDetailsImpl) SecurityContextHolder
                .getContext()
                .getAuthentication()
                .getPrincipal();
                
            // 添加发起人变量
            dto.getVariables().put("initiator", userDetails.getId());
            
            processService.startProcess(dto.getProcessDefinitionKey(), dto.getVariables());
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            log.error("Start process failed", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    @GetMapping("/my-requests")
    public ResponseEntity<List<ProcessRequest>> getMyRequests() {
        try {
            // 获取当前用户
            UserDetailsImpl userDetails = (UserDetailsImpl) SecurityContextHolder
                .getContext()
                .getAuthentication()
                .getPrincipal();
                
            List<ProcessRequest> requests = processService.getMyRequests(userDetails.getId());
            return ResponseEntity.ok(requests);
        } catch (Exception e) {
            log.error("Failed to get my requests", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    @GetMapping("/process-instances/{processInstanceId}")
    public ResponseEntity<?> getProcessInstance(@PathVariable String processInstanceId) {
        try {
            Map<String, Object> processInstance = processService.getProcessInstanceDetails(processInstanceId);
            return ResponseEntity.ok(processInstance);
        } catch (Exception e) {
            log.error("Failed to get process instance details", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("获取流程实例详情失败: " + e.getMessage()));
        }
    }
} 